﻿using System.Collections.Generic;
using System.Reflection;

namespace Mbs.Reflection
{
    class DynamicMethodFactoryProxy:IDynamicMethodFactory
    {
        private IDynamicMethodFactory RealFactory = new DynamicMethodFactory();
        private Dictionary<MethodInfo, Proc> actionCache = new Dictionary<MethodInfo, Proc>();
        private Dictionary<MethodInfo, Func> funcCache = new Dictionary<MethodInfo, Func>();
        private Dictionary<ConstructorInfo, ConstructorHandler> factoryMethodCache = new Dictionary<ConstructorInfo, ConstructorHandler>();
        private Dictionary<FieldInfo, Getter> getterFieldCache = new Dictionary<FieldInfo, Getter>();
        private Dictionary<PropertyInfo, Getter> getterPropertyCache = new Dictionary<PropertyInfo, Getter>();
        private Dictionary<FieldInfo, Setter> setterFieldCache = new Dictionary<FieldInfo, Setter>();
        private Dictionary<PropertyInfo, Setter> setterPropertyCache = new Dictionary<PropertyInfo, Setter>();

        private DynamicMethodFactoryProxy() { }

        public static readonly DynamicMethodFactoryProxy Instance = new DynamicMethodFactoryProxy();

        #region IDynamicMethodFactory Members
        public Proc CreateProcMethod(System.Reflection.MethodInfo method)
        {
            Proc result = null;
            if (!actionCache.TryGetValue(method, out result))
            {
                result = RealFactory.CreateProcMethod(method);
                actionCache[method] = result;
            }
            return result;
        }

        public Func CreateFuncMethod(System.Reflection.MethodInfo method)
        {
            Func result = null;
            if (!funcCache.TryGetValue(method, out result))
            {
                result = RealFactory.CreateFuncMethod(method);
                funcCache[method] = result;
            }
            return result;
        }

        public ConstructorHandler CreateConstructorMethod(System.Reflection.ConstructorInfo constructor)
        {
            ConstructorHandler result = null;
            if (!factoryMethodCache.TryGetValue(constructor, out result))
            {
                result = RealFactory.CreateConstructorMethod(constructor);
                factoryMethodCache[constructor] = result;
            }
            return result;
        }

        public Getter CreateGetter(System.Reflection.FieldInfo field)
        {
            Getter result = null;
            if (!getterFieldCache.TryGetValue(field, out result))
            {
                result = RealFactory.CreateGetter(field);
                getterFieldCache[field] = result;
            }
            return result;
        }

        public Getter CreateGetter(System.Reflection.PropertyInfo property)
        {
            Getter result = null;
            if (!getterPropertyCache.TryGetValue(property, out result))
            {
                result = RealFactory.CreateGetter(property);
                getterPropertyCache[property] = result;
            }
            return result;
        }

        public Setter CreateSetter(System.Reflection.FieldInfo field)
        {
            Setter result = null;
            if (!setterFieldCache.TryGetValue(field, out result))
            {
                result = RealFactory.CreateSetter(field);
                setterFieldCache[field] = result;
            }
            return result;
        }

        public Setter CreateSetter(System.Reflection.PropertyInfo property)
        {
            Setter result = null;
            if (!setterPropertyCache.TryGetValue(property, out result))
            {
                result = RealFactory.CreateSetter(property);
                setterPropertyCache[property] = result;
            }
            return result;
        }

        #endregion
    }
}
